<template>
  <!-- 人工智能AI助手 -->
  <div id="ai-global-toolbar">
    <!-- 弹出窗口 -->
    <div :class="isOpen ? 'ai-toolbar-wrap ai-toolbar-pen' : 'ai-toolbar-wrap'">
      <!--内层容器，包含弹出工具区域和工具按钮 定位是relative-->
      <div class="ai-toolbar-container">
        <div class="ai-toolbar-panel">
          <!-- 聊天窗口 -->
          <div class="ai-chat-container">
            <!-- 聊天标题 -->
            <div class="ai-title-panel">
              <div class="title">
                <h4>欢迎使用AI助手</h4>
                <span class="test">内测版</span>
              </div>
              <div>
                大语言模型来自：<a
                  href="https://www.deepseek.com/"
                  target="blank"
                  >DeepSeek-R1</a
                >
              </div>
            </div>
            <!-- 聊天内容框 -->
            <div class="ai-chat-content">
              <ChatDialogComponents 
                :AI_OutList="ai_outputList" 
                :AI_StopByUser="isStoppedByUser"
              />
            </div>
          </div>
          <!-- 聊天输入 -->
          <div class="ai-chat-input-panel">
            <div class="ai-loading" v-if="ai_loading">AI思考中...点击发送按钮停止输出</div>
            <div class="ai-input-commit">
              <el-input
                class="chat-input"
                placeholder="请输入你的问题,并按Enter提问"
                v-model="user_input"
                @keyup.enter="NewStreamChat"
                clearable
                :disabled="ai_loading"
              />
              <!-- 替换原来的按钮为新的样式 -->
              <div class="ds-button-area">
                <div v-if="!ai_loading" class="send-area" @click="NewStreamChat">
                  <div class="ds-icon">
                    <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1024 1024">
                      <path fill="currentColor" d="m64 448 832-320-128 704-446.08-243.328L832 192 242.816 545.472zm256 512V657.024L512 768z"></path>
                    </svg>
                  </div>
                </div>
                <div v-else class="send-area" @click="stopOutput">
                  <div class="ds-icon-stop"></div>
                </div>
              </div>
            </div>
          </div>
        </div>
        <div class="ai-toolbar-buttons">
          <div class="ai-tbar-list">
            <div class="ai-tbar-item" @click="openAIWindows">
              <i class="tbar_icon">Ai</i>
              <em class="tab-text">AI助手</em>
            </div>
          </div>
        </div>
      </div>
    </div>
  </div>
</template>

<script setup>
import { ref, reactive, computed, onMounted, nextTick } from "vue";
import ChatDialogComponents from "@/components/ChatDialogComponents.vue";

// 系统提示词
const SYSTEM_PROMPT = {
  role: "system",
  content:
    "你是一个由深度求索公司开发的人工智能助手,名为deepseek-R1。你非常专业、友好且富有同理心。你会以简洁清晰的方式回答问题,并始终保持谦逊和真诚。当你不确定某件事时,你会坦诚地承认。你会避免任何有害或不当的内容。",
};

const isOpen = ref(false);
const user_input = ref("");
const ai_output = ref("");
const ai_outputList = ref([]);
const ai_loading = ref(false);
const init_message = ref([]);
const isStoppedByUser = ref(false);
const startTime = ref(0);
const totalTokens = ref(0);

const openAIWindows = () => {
  isOpen.value = !isOpen.value;
};

const scrollToBottom = () => {
  nextTick(() => {
    var container = document.querySelector(".ai-chat-content");
    container.scrollTop = container.scrollHeight;
  });
};

const replaceMathSymbols = (inputStr) => {
  let replacedStr;
  replacedStr = inputStr
    .replace(/\\\[(\s*)/g, "$$")
    .replace(/(\s*)\\\]/g, "$$");
  replacedStr = replacedStr
    .replace(/\\\((\s*)/g, "$")
    .replace(/(\s*)\\\)/g, "$");
  return replacedStr;
};

const processAIResponse = (content, isCompleting = false) => {
  const thinkEndIndex = content.indexOf("</think>");
  let thinking = content;
  let answer = "";
  let isThinkedAnswer = false;

  if (thinkEndIndex > -1) {
    thinking = content.slice(0, thinkEndIndex).trim();
    answer = content.slice(thinkEndIndex + 8).trim();
    isThinkedAnswer = true;
  } else if (isCompleting) {
    thinking = "";
    answer = content;
    isThinkedAnswer = false;
  }

  return {
    thinking,
    answer,
    isThinkedAnswer,
    isStopped: isStoppedByUser.value,
  };
};

const NewStreamChat = async () => {
  if (ai_loading.value || !user_input.value.trim()) return;

  isStoppedByUser.value = false;
  ai_loading.value = true;
  startTime.value = Date.now();
  totalTokens.value = 0;

  try {
    const prompt = user_input.value;
    user_input.value = "";
    ai_output.value = "";
    
    // 添加用户消息到显示列表和对话历史
    const userMessage = { role: "user", content: prompt };
    ai_outputList.value.push(userMessage);
    init_message.value.push(userMessage);
    
    scrollToBottom();

    const response = await fetch("http://localhost:8000/v1/chat/completions", {
      method: "POST",
      headers: {
        "Content-Type": "application/json",
      },
      body: JSON.stringify({
        messages: init_message.value,
        max_tokens: 2048,
        temperature: 0.1,
        stream: true,
      }),
    });

    if (!response.body) {
      throw new Error("服务器未返回流数据");
    }

    const reader = response.body.getReader();
    const decoder = new TextDecoder("utf-8");
    let buffer = "";

    ai_outputList.value.push({ role: "assistant", content: "" });

    while (true) {
      const { done, value } = await reader.read();
      if (done) {
        break;
      }
      const chunk = decoder.decode(value, { stream: true });
      // console.log("流数据：", chunk);

      buffer += chunk;

      const lines = buffer.split("\n");
      buffer = lines.pop();
      for (const line of lines) {
        if (line.startsWith("data: ")) {
          const jsonStr = line.slice(6).trim();
          if (jsonStr !== "[DONE]") {
            try {
              const jsonData = JSON.parse(jsonStr);
              const content = jsonData?.choices[0]?.delta?.content || "";
              if (content) {
                totalTokens.value += content.length;
                const newContent = ai_output.value + content;
                const { thinking, answer, isThinkedAnswer } = processAIResponse(newContent, false);

                ai_output.value += content;
                const lastMsg = ai_outputList.value[ai_outputList.value.length - 1];
                lastMsg.content += content;
                lastMsg.content = replaceMathSymbols(lastMsg.content);
                lastMsg.thinking = thinking;
                lastMsg.answer = answer;
                lastMsg.isThinkedAnswer = isThinkedAnswer;
                lastMsg.isThinkingExpand = true;

                scrollToBottom();
              }
            } catch (error) {
              console.error("解析 JSON 数据失败:", error, line);
            }
          } else {
            const lastMsg = ai_outputList.value[ai_outputList.value.length - 1];
            lastMsg.isCompleted = true;
            const endTime = Date.now();
            const duration = (endTime - startTime.value) / 1000;
            lastMsg.tokenRate = Math.round(totalTokens.value / duration);

            init_message.value.push({
              role: "assistant",
              content: ai_output.value,
            });
            scrollToBottom();
          }
        }
      }
    }
    ai_outputList.value[ai_outputList.value.length - 1].content =
      replaceMathSymbols(
        ai_outputList.value[ai_outputList.value.length - 1].content
      );
    ai_loading.value = false;
  } catch (error) {
    console.error("流数据请求失败:", error);
  } finally {
    ai_loading.value = false;
  }
};

const stopOutput = async () => {
  if (!ai_loading.value) return;

  isStoppedByUser.value = true;
  ai_loading.value = false;

  const endTime = Date.now();
  const duration = (endTime - startTime.value) / 1000;
  const tokenRate = Math.round(totalTokens.value / duration);

  const lastMsg = ai_outputList.value[ai_outputList.value.length - 1];
  if (lastMsg) {
    lastMsg.isCompleted = true;
    lastMsg.tokenRate = tokenRate;
    lastMsg.isStopped = true;
  }

  await fetch("http://localhost:8000/api/stop_generation", {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify({ confirm: true }),
  });
};

onMounted(() => {
  init_message.value = [SYSTEM_PROMPT];
});
</script>

<style scoped>
#ai-global-toolbar {
  display: block;
}
.ai-toolbar-wrap {
  position: fixed;
  height: 100%;
  top: 0;
  right: -600px;
  z-index: 2999;
  transition: right 0.5s;
}

.ai-toolbar-pen {
  right: 0px;
}

.ai-toolbar-container {
  position: relative;
  width: 600px;
  height: 100%;
}

.ai-toolbar-panel {
  position: relative;
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  width: 600px;
  height: 100%;
  background-color: #fcfbfb;
  border-left: solid 4px rgb(74, 175, 241);
  z-index: 99;
}

.ai-toolbar-buttons {
  position: absolute;
  top: 0;
  left: 1px;
  height: 100%;
}

.ai-tbar-list {
  position: absolute;
  top: 50%;
  right: 0;
  margin-top: -61px;
  width: 35px;
}

.ai-tbar-item {
  position: relative;
  width: 35px;
  height: 35px;
  margin-bottom: 1px;
  cursor: pointer;
  text-align: center;
  line-height: 35px;
  border-radius: 3px 0 0 3px;
}

.ai-tbar-item .tbar_icon {
  position: relative;
  z-index: 5;
  width: 34px;
  height: 35px;
  display: block;
  margin-left: 1px;
  background-color: rgb(140, 143, 145);
  border: solid 1px rgba(255, 255, 255, 1);
  border-radius: 5px 0 0 5px;
  color: #ffffff;
  font-size: 20px;
}

.ai-tbar-item .tbar_icon:hover {
  background-color: rgb(74, 175, 241);
  border-left: solid 1px rgba(255, 255, 255, 0);
  border-radius: 0;
}

.tab-text {
  width: 62px;
  height: 35px;
  line-height: 35px;
  color: #fff;
  text-align: center;
  font-family: 微软雅黑;
  position: absolute;
  left: 35px;
  font-size: 12px;
  font-style: normal;
  z-index: 4;
  top: 0;
  background-color: rgb(74, 175, 241);
  border: solid 1px #ffffff;
  border-radius: 5px 0 0 5px;
  border-radius: 3px 0 0 3px;
  transition: left 0.3s;
}

.ai-tbar-item .tbar_icon:hover + .tab-text {
  left: -60px;
}

/* AI区域内容样式 */
/* 标题部分 */
.ai-title-panel {
  display: flex;
  flex-direction: column;
  width: 100%;
  margin-bottom: 30px;
}

.ai-title-panel > div {
  display: flex;
  justify-content: center;
  font-size: 12px;
}

.title {
  position: relative;
  margin-top: 30px;
  display: flex;  /* 添加 flex 布局 */
  align-items: center;  /* 垂直居中对齐 */
  justify-content: center;  /* 水平居中对齐 */
}

.title h4 {
  font-weight: 700;
  margin: 0;  /* 移除默认外边距 */
  font-size: 22px;
  line-height: 1.5;  /* 调整行高 */
}

.title .test {
  border: 1px solid rgb(3, 150, 248);
  color: rgb(3, 150, 248);
  border-radius: 3px;
  padding: 0 3px;
  height: 18px;
  line-height: 18px;
  margin-left: 5px;
  font-size: 12px;  /* 调整字体大小 */
  display: inline-flex;  /* 使用 inline-flex */
  align-items: center;  /* 垂直居中 */
}

/* 内容部分 */
.ai-chat-content {
  position: relative;
  padding: 10px 10px;
  background: #ffffff;
  height: calc(100vh - 115px - 150px);
  overflow-y: auto;
  font-size: 16px;
  color: #000;
}

.chat-dialog {
  padding: 0 10px;
}

/* 动态html样式不生效 */
:deep(.question) {
  font-weight: 700;
  margin-top: 10px;
}
/* 聊天输入 */

.ai-chat-input-panel {
  display: flex;
  flex-direction: column;
  margin-bottom: 70px;
  padding: 10px;
}

.ai-loading {
  font-size: 15px;
  line-height: 16px;
  margin: 10px 0;
  color: #666;
  font-size: 13px;
  text-align: center;
  margin-bottom: 8px;
}

.ai-input-commit {
  display: flex;
  width: 100%;
}

.ds-button-area {
  white-space: nowrap;
}

.send-area {
  white-space: nowrap;
  cursor: pointer;
  color: #fff;
  background: #4d6bfe;
  border: none;
  border-radius: 6px;
  flex-direction: column;
  flex-shrink: 0;
  justify-content: center;
  align-items: center;
  min-width: 32px;
  height: 32px;
  margin-top: auto;
  display: flex;
}

.send-area:hover {
  background: #2563eb;
}

.ds-icon {
  font-size: 16px;
  width: 16px;
  height: 16px;
}

.ds-icon svg {
  width: 100%;
  height: 100%;
}

.ds-icon-stop {
  width: 12px;
  height: 12px;
  background: rgb(252, 250, 250);
  border-radius: 2px;
}

/* 调整输入框样式以配合新按钮 */
.chat-input {
  margin-right: 8px;
}

/* 移除旧的按钮样式 */
.ai-button {
  display: none;
}

a {
  text-decoration: none;
}

a:hover {
  color: #f15323;
}

/* 自定义滚动条的整体样式 */
::-webkit-scrollbar {
  width: 12px;
}

/* 自定义滚动轨迹的样式 */
::-webkit-scrollbar-track {
  background: #f1f1f1;
}

/* 自定义滚动滑块的样式 */
::-webkit-scrollbar-thumb {
  background-color: rgb(99, 188, 247);
  border-radius: 6px;
  border: 3px solid transparent;
  background-clip: content-box;
}

/* 当鼠标悬停在滚动滑块上时的样式 */
::-webkit-scrollbar-thumb:hover {
  background-color: rgb(45, 165, 246);
}

/* 添加停止按钮样式 */
.stop-icon {
  width: 14px;
  height: 14px;
  background: rgb(252, 250, 250);
  border-radius: 2px;
}

/* 禁用状态的输入框样式 */
:deep(.el-input.is-disabled .el-input__inner) {
  background-color: #f5f7fa;
  border-color: #e4e7ed;
  color: #c0c4cc;
  cursor: not-allowed;
}
</style>